Lógica sintáctica en R base

Con R base nos referimos a los comandos básicos que vienen incorporados en el R, sin necesidad de cargar librerías.

Objetos

Los Objetos/Elementos constituyen la categoría escencial del R. De hecho, todo en R es un objeto, y se almacena con un nombre específico que no debe poseer espacios. Un número, un vector, una función, la progresión de letras del abecedario, una base de datos, un gráfico, constituyen para R objetos de distinto tipo. Los objetos que vamos creando a medida que trabajamos pueden visualizarse en la panel derecho superior de la pantalla (“Environment”).

Operadores

Los operadores son los símbolos que le indican a R que debe realizar una tarea. Mediante la combinación de datos y operadores es que logramos que R haga su trabajo.

Existen operadores específicos para cada tipo de tarea. Los tipos de operadores principales son los siguientes:

  • De asignación
  • Aritméticos
  • Relacionales
  • Lógicos

Operadores de asignación

  • \(<-\)
  • \(=\)

Ambos operadores sirven para definir objetos, es decir, asignarle un valor. Sin embargo, en la práctica se suele utilizar el operador <- para la definición de objetos, por más que el = sea equivalente. A la izquierda del <- debe ubicarse el nombre que tomará el elemento a crear. Del lado derecho debe ir la definición del mismo.

Veamos un ejemplo:

A <- 1
A 
[1] 1

Al definir un elemento, el mismo queda guardado en el ambiente del programa, y podrá ser utilizado posteriormente para observar su contenido o para realizar una operación con el mismo.

A + 6
[1] 7

Al correr una linea con el nombre del objeto, la consola del programa nos muestra su contenido. Entre corchetes observamos el número de orden del elemento en cuestión.

B <- 2
B
[1] 2

<- es un operador Unidireccional, es decir que:

A <- B implica que A va tomar como valor el contenido del objeto B, y no al revés.

A <- B

#Ahora A toma el valor de B, y B continua conservando el mismo valor
A   
[1] 2
B
[1] 2

En R, cuando se define un objeto con el mismo nombre de un objeto previamente existente, el último reemplaza al primero.

Operadores aritméticos:

  • Suma: \(+\)
  • Resta: \(-\)
  • Cociente: \(/\)
  • Multiplicación: \(*\)
#suma
A <- 5+6
A
[1] 11
#Resta
B <- 6-8
B
[1] -2
#cociente
C <- 6/2
C
[1] 3
#multiplicacion
D <- 6*2
D
[1] 12

Operadores lógicos relacionales:

Los operadores lógicos son usados para describir relaciones, expresadas como verdadero (TRUE) o falso (FALSE).

  • Mayor: \(>\)
  • Mayor o igual: \(>=\)
  • Menor: \(<\)
  • Menor o igual: \(<=\)
  • Igual: \(==\)
  • Distinto: \(!=\)
#Redefinimos los valores A y B
A <- 10
B <- 20

#Realizamos comparaciones lógicas
A > B
[1] FALSE
A >= B
[1] FALSE
A < B
[1] TRUE
A <= B
[1] TRUE
A == B
[1] FALSE
A != B
[1] TRUE
C <- A != B
C
[1] TRUE

Como muestra el último ejemplo, el resultado de una operación lógica puede almacenarse como el valor de un objeto.

Otros operadores lógicos:

  • Ó: \(|\)
  • Y: \(&\)
#Redefinimos los valores A y B
A <- 10
B <- 20
#Realizamos comparaciones lógicas

(A | B) > 30
[1] FALSE
(A & B) <= 30
[1] TRUE

Caracteres especiales

  • R es sensible a mayúsculas y minúsculas, tanto para los nombres de las variables, como para las funciones y parámetros.
  • Los espacios en blanco y los carriage return (enter) no son considerados por el lenguaje. Los podemos aprovechar para emprolijar el código y que la lectura sea más simple1.
  • El numeral # se utiliza para hacer comentarios. Todo lo que se escribe después del # no es interpretado por R. Se debe utilizar un # por cada línea de código que se desea anular

  • Los corchetes [] se utilizan para acceder a un objeto:

    • en un vector[n° orden]
    • en una tabla[fila, columna]
    • en una lista[n° elemento]
  • el signo $ también es un método de acceso. Particularmente, en los dataframes, nos permitira acceder a una determinada columna de una tabla

  • Los paréntesis() se utilizan en las funciones para definir los parámetros.

  • Las comas , se utilizan para separar los parametros al interior de una función.


Tipos de Objetos:

Existen un gran cantidad de objetos distintos en R, en lo que respecta al curso trabajaremos principalmente con 4 de ellos:

  • Valores
  • Vectores
  • Data Frames
  • Listas

Valores

Los valores pueden ser de distintas clases o tipos:

Valores “Numeric” (numéricos)

A <- 1
class(A)
[1] "numeric"


Valores ‘Character’ (caracter)

A <- "Hola"
class(A)
[1] "character"
A <- "Hola, ¿qué tal?"
class(A)
[1] "character"
A <- paste('Hola,', '¿qué tal?', sep = " ")
A
[1] "Hola, ¿qué tal?"
class(A)
[1] "character"


Valores de tipo ‘factor’

En general, es un dato numérico representado por una etiqueta.

valor1 <- "A"
class(valor1)
[1] "character"
valor2 <- factor("A")
valor2
[1] A
Levels: A
# Otra forma de definir al factor
valor2 <- factor(valor1)
valor2
[1] A
Levels: A
class(valor2)
[1] "factor"
# Una propiedad del factor: las etiquetas.
valor3 <- factor("A",
                 labels = "Letra A")
class(valor3)
[1] "factor"
valor3
[1] Letra A
Levels: Letra A


La diferencia entre un character y un factor es que el último tiene solo algunos valores permitidos (levels), con un orden interno predefinido (el cual ,por ejemplo, se respetará a la hora de realizar un gráfico)

Vectores

Un vector es un conjunto de datos de un mismo tipo. En otras palabras, es un conjunto de valores de la misma clase. Puede haber vectores númericos, character, factores. Los vectores constituyen la estructura de datos más sencilla de R.

Para crear un vector utilizamos el comando c(), de combinar.

# Vector numérico
A <- c(1, 2, 2, 2, 1, 1, 1)
A
[1] 1 2 2 2 1 1 1
class(A)
[1] "numeric"
# Vector de caracteres
B <- c("Uno", "Dos", "Dos", "Dos", "Uno", "Uno", "Uno")
B
[1] "Uno" "Dos" "Dos" "Dos" "Uno" "Uno" "Uno"
class(B)
[1] "character"
# Vector de tipo factor
C <- as.factor(A)
C
[1] 1 2 2 2 1 1 1
Levels: 1 2
class(C)
[1] "factor"
# Defino etiquetas del vector numérico o caracter
A
[1] 1 2 2 2 1 1 1
A_etiquetas <- factor(A,
                     labels = c('Varón','Mujer'))
A_etiquetas
[1] Varón Mujer Mujer Mujer Varón Varón Varón
Levels: Varón Mujer

Con los vectores numéricos se pueden hacer operaciones como, por ejemplo: * sumarle 2 a cada elemento del vector anterior.

D <- c(1, 3, 4)
D <- D + 2
D
[1] 3 5 6
  • sumarle 1 al primer elemento, 2 al segundo, y 3 al tercer elemento del vector anterior
E <- D + 1:3 #esto es equivalente a hacer 3+1, 5+2, 6+9 
E
[1] 4 7 9

1:3 significa que queremos todos los números enteros desde 1 hasta 3.


En R podemos quedarnos con algunos elemenos de los vectores para trabajar con o sobre ellos. Para acceder a un elemento del vector podemos buscarlo a través del número de orden, identificando al mismo utilizando los signos [ ]

# Si quiero al elemento 2 del objeto E:
E 
[1] 4 7 9
E[2]
[1] 7

Si nos interesa quedarnos con dicho valor, al buscarlo lo asignamos a un nuevo objeto.

E_posicion2 <-  E[2]
E_posicion2
[1] 7

Para borrar un objeto del ambiente de trabajo, utilizamos la función rm()

rm(E_posicion2)
#E_posicion2

También podemos cambiar el texto del segundo elemento de E, por el texto “Pablo”

E
[1] 4 7 9
E[2] <- "Pablo"
E
[1] "4"     "Pablo" "9"    
# Tener cuidado al modificar el tipo de uno de los valores y no el de todos los del objeto:
class(E)
[1] "character"

Data Frames (o bases de datos)

Un Data Frame es una estructura de datos de 2 dimensiones o tabla, donde cada columna representa una variable, y cada fila una observación.

Los data frames pueden contener datos de diferentes clases. Puede ser considerado como un conjunto de vectores de igual tamaño, donde cada vector (columna) tiene que tener datos del mismo tipo, pero las clases de vectores que conforman la tabla pueden ser distintas. Entonces, cada observación (fila) está compuesta por datos que pueden ser de distinto tipo.

Este objeto es central en el proceso de trabajo, ya que es la estructura más usada para realizar análisis de datos, y suele ser la forma en que se cargan datos externos para trabajar en el ambiente de R, y en que se exportan los resultados de nuestros trabajo.

Veamos un ejemplo de data frame creado a partir de la combinación de vectores:

AGLOMERADO  <- c(32,33,33,33,32)

SEXO  <-  c("Varon","Mujer","Mujer","Varon","Mujer")

EDAD  <-  c(60,54,18,27,32)

Datos <- data.frame(AGLOMERADO, SEXO, EDAD)
Datos
class(Datos)
[1] "data.frame"

Tal como en un vector podemos acceder a los elementos a través de los [ ], en un dataframe lo hacemos de la forma [fila, columna].

En los Data.Frames tenemos, por definición, más de una columna (variable). Para acceder a alguna de ellas podemos utilizar el operador $.

Datos$AGLOMERADO[2]
[1] 33

¿que pasa si hacemos Datos$AGLOMERADO[3,2] ?

Datos$AGLOMERADO[3,2]

Nótese que el último comando tiene un número incorrecto de dimensiones, porque estamos refiriendonos 2 veces a la columna AGLOMERADO.

Acorde a lo visto anteriormente, el acceso a los dataframes mediante [ ] puede utilizarse también para realizar filtros (devolver el o los valores en función de otro valor definido). Por ejemplo, puedo utilizar los [ ] para obtener del dataframe Datos unicamente los registros del AGLOMERADO 32:

Datos[Datos$AGLOMERADO==32, ]

La lógica del paso anterior sería: Accedo al dataframe Datos, pidiendo únicamente conservar las filas (por eso la condición se ubica a la izquierda de la ,) que cumplan el requisito de pertenecer a la categoría 32 de la variable AGLOMERADO.

Aún más, podría aplicar el filtro y al mismo tiempo identificar una variable de interés para luego realizar un cálculo sobre aquella. Por ejemplo, podría calcular la media de la edad para aquellas personas que residen en el aglomerado 32.

###Por separado
Edad_Aglo32 <- Datos$EDAD[Datos$AGLOMERADO==32]
Edad_Aglo32
mean(Edad_Miembro1)
Error in mean(Edad_Miembro1) : objeto 'Edad_Miembro1' no encontrado

La lógica de esta sintaxis sería: “Me quedó con la variable EDAD, cuando la variable AGLOMERADO sea igual a 32, luego calculo la media de dichos valores”


Listas

Contienen una concatenación de objetos de cualquier tipo. Así como un vector contiene valores, un dataframe contiene vectores, una lista puede contener dataframes, pero también vectores, o valores, y todo ello a la vez

LISTA <- list(A,B,C,D,E,Datos$AGLOMERADO, DF = Datos)
LISTA
[[1]]
[1] 1 2 2 2 1 1 1

[[2]]
[1] "Uno" "Dos" "Dos" "Dos" "Uno" "Uno" "Uno"

[[3]]
[1] 1 2 2 2 1 1 1
Levels: 1 2

[[4]]
[1] 3 5 6

[[5]]
[1] "4"     "Pablo" "9"    

[[6]]
[1] 32 33 33 33 32

$DF
NA

Tal como para con los Vectores y los Data.Frames, podemos acceder a un elemento de una lista, utilizando el operador $:

LISTA$DF
LISTA$DF$EDAD
[1] 60 54 18 27 32
LISTA$DF$EDAD[2]
[1] 54

También se pueden usar corchetes dobles [[]] para acceder a los distintos elementos de una lista.

LISTA[[6]]
[1] 32 33 33 33 32

O para acceder a un valor/vector (dependiendo del tipo de elemento de la lista) de un objeto de la lista:

LISTA[[6]][1]
[1] 32
LISTA[[7]][2]

LISTA[[7]][2,1]
[1] 33

Funciones (las herramientas del armario):

Las funciones son series de procedimientos estandarizados, que toman como imput determinados argumentos a fijar por el usuario (llamados parámetros), y devuelven un resultado acorde a la aplicación de dichos procedimientos. Su lógica de funcionamiento es:
funcion(argumento1 = arg1, argumento2 = arg2)

A lo largo del curso iremos viendo numerosas funciones, según lo requieran los distintos ejercicios. Sin embargo, veamos ahora algunos ejemplos para comprender su funcionamiento:

  • paste() : concatena una serie de caracteres, indicando por última instancia como separar a cada uno de ellos
  • paste0(): concatena una serie de caracteres sin separar
  • sum(): suma de todos los elementos de un vector
  • mean() promedio aritmético de todos los elementos de un vector
paste("Pega","estas", 4, "palabras", sep = " ")
[1] "Pega estas 4 palabras"
#Puedo concatenar caracteres almacenados en objetos
a <- c(1, 2, 3)
b <- "con"
c <- c(4, 5, 6)

paste(a,b,c,sep = "-")
[1] "1-con-4" "2-con-5" "3-con-6"
# Paste0 pega los caracteres sin separador
paste0(a,b,c)
[1] "1con4" "2con5" "3con6"
# ¿Te acordás del comando que usamos?
1:5
[1] 1 2 3 4 5
# Función para sumar
sum(1:5)
[1] 15
# Para calclar medias
mean(1:5)
[1] 3

Instalación de paquetes complementarios al R Base (¡más cajas de herramientas para el armarrio!)

Hasta aquí hemos visto múltiples funciones que están contenidas dentro del lenguaje básico de R. Ahora bien, al tratarse de un software libre, distintos usuarios de R contribuyen sistemáticamente a expandir este lenguaje mediante la creación y actualización de paquetes complementarios. Lógicamente, los mismos no están incluidos en la instalación inicial del programa, pero podemos descargarlos e instalarlos con el siguiente comando:

install.packages("nombre_del_paquete") 

Al ejecutar el comando se descargarán de la pagina de CRAN los archivos correspondientes al paquete hacia el directorio en donde hayamos instalado el programa. Típicamente los archivos se encontrarán en **C:Files.0**, siempre con la versión del programa correspondiente.

Los paquetes sólo se instalan una vez en la computadora (si cambias de computadora, tenés que volver a instalarlo). Una vez instalado el paquete, cada vez que abramos una nueva sesión de R y querramos utilizar el mismo debemos cargarlo al ambiente de trabajo mediante la siguiente función:

library(nombre_del_paquete)

Nótese que al cargar/activar el paquete no son necesarias las comillas.

Paquetes a utilizar a lo largo del curso:

Para quienes esten trabajando con sus computadoras personales, dejamos a continuación un listado de los paquetes complementarios del R base que utilizaremos a lo largo del curso. Como la instalación requiere descargar múltiples archivos de internet recomendamos hacerlo cuando dispongan de una buena conexión. Con el siguiente comando podrían instalarlos todos de una vez:

install.packages(c("tidyverse","openxlsx",'ggplot2','ggthemes', 'ggrepel','ggalt','kableExtra', 'rmarkdown'))

  1. veremos que existen ciertas excepciones con algunos paquetes más adelante.↩︎

LS0tDQp0aXRsZTogIkludHJvZHVjY2nDs24gYWwgbGVuZ3VhamUgUiINCnNpdGU6IGRpc3RpbGw6OmRpc3RpbGxfd2Vic2l0ZQ0KLS0tDQogIA0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpDQpgYGANCg0KIyBMw7NnaWNhIHNpbnTDoWN0aWNhIGVuIFIgYmFzZQ0KDQpDb24gX1IgYmFzZV8gbm9zIHJlZmVyaW1vcyBhIGxvcyBjb21hbmRvcyBiw6FzaWNvcyBxdWUgdmllbmVuIGluY29ycG9yYWRvcyBlbiBlbCBSLCBzaW4gbmVjZXNpZGFkIGRlIGNhcmdhciBsaWJyZXLDrWFzLiANCg0KIyMgT2JqZXRvcw0KTG9zIF9fT2JqZXRvcy9FbGVtZW50b3NfXyBjb25zdGl0dXllbiBsYSBjYXRlZ29yw61hIGVzY2VuY2lhbCBkZWwgUi4gRGUgaGVjaG8sIHRvZG8gZW4gUiBlcyB1biBvYmpldG8sIHkgc2UgYWxtYWNlbmEgY29uIHVuIG5vbWJyZSBlc3BlY8OtZmljbyBxdWUgKipubyBkZWJlIHBvc2VlciBlc3BhY2lvcyoqLiBVbiBuw7ptZXJvLCB1biB2ZWN0b3IsIHVuYSBmdW5jacOzbiwgbGEgcHJvZ3Jlc2nDs24gZGUgbGV0cmFzIGRlbCBhYmVjZWRhcmlvLCB1bmEgYmFzZSBkZSBkYXRvcywgdW4gZ3LDoWZpY28sIGNvbnN0aXR1eWVuIHBhcmEgUiBvYmpldG9zIGRlIGRpc3RpbnRvIHRpcG8uIExvcyBvYmpldG9zIHF1ZSB2YW1vcyBjcmVhbmRvIGEgbWVkaWRhIHF1ZSB0cmFiYWphbW9zIHB1ZWRlbiB2aXN1YWxpemFyc2UgZW4gbGEgcGFuZWwgZGVyZWNobyBzdXBlcmlvciBkZSBsYSBwYW50YWxsYSAoIkVudmlyb25tZW50IikuIA0KDQoNCiMjIE9wZXJhZG9yZXMNCg0KTG9zIG9wZXJhZG9yZXMgc29uIGxvcyBzw61tYm9sb3MgcXVlIGxlIGluZGljYW4gYSBSIHF1ZSBkZWJlIHJlYWxpemFyIHVuYSB0YXJlYS4gTWVkaWFudGUgbGEgY29tYmluYWNpw7NuIGRlIGRhdG9zIHkgb3BlcmFkb3JlcyBlcyBxdWUgbG9ncmFtb3MgcXVlIFIgaGFnYSBzdSB0cmFiYWpvLg0KDQpFeGlzdGVuIG9wZXJhZG9yZXMgZXNwZWPDrWZpY29zIHBhcmEgY2FkYSB0aXBvIGRlIHRhcmVhLiBMb3MgdGlwb3MgZGUgb3BlcmFkb3JlcyBwcmluY2lwYWxlcyBzb24gbG9zIHNpZ3VpZW50ZXM6DQoNCiogRGUgYXNpZ25hY2nDs24NCiogQXJpdG3DqXRpY29zDQoqIFJlbGFjaW9uYWxlcw0KKiBMw7NnaWNvcw0KDQoNCiMjIyBPcGVyYWRvcmVzIGRlIGFzaWduYWNpw7NuDQoNCi0gJDwtJA0KLSAkPSQNCg0KQW1ib3Mgb3BlcmFkb3JlcyBzaXJ2ZW4gcGFyYSBkZWZpbmlyIG9iamV0b3MsIGVzIGRlY2lyLCBhc2lnbmFybGUgdW4gdmFsb3IuIA0KU2luIGVtYmFyZ28sIGVuIGxhIHByw6FjdGljYSBzZSBzdWVsZSB1dGlsaXphciBlbCBvcGVyYWRvciBfX2BgYDwtYGBgX18gcGFyYSBsYSBkZWZpbmljacOzbiBkZSBvYmpldG9zLCBwb3IgbcOhcyBxdWUgZWwgX19gYGA9YGBgX18gc2VhIGVxdWl2YWxlbnRlLiAgX19BIGxhIGl6cXVpZXJkYV9fIGRlbCBfX2BgYDwtYGBgX18gZGViZSB1YmljYXJzZSBlbCBub21icmUgcXVlIHRvbWFyw6EgZWwgZWxlbWVudG8gYSBjcmVhci4gX19EZWwgbGFkbyBkZXJlY2hvX18gZGViZSBpciBsYSBkZWZpbmljacOzbiBkZWwgbWlzbW8uDQoNClZlYW1vcyB1biBlamVtcGxvOg0KYGBge3J9DQpBIDwtIDENCkEgDQpgYGANCg0KICANCkFsIGRlZmluaXIgdW4gZWxlbWVudG8sIGVsIG1pc21vIHF1ZWRhIGd1YXJkYWRvIGVuIGVsIGFtYmllbnRlIGRlbCBwcm9ncmFtYSwgeSBwb2Ryw6Egc2VyIHV0aWxpemFkbyBwb3N0ZXJpb3JtZW50ZSBwYXJhIG9ic2VydmFyIHN1IGNvbnRlbmlkbyBvIHBhcmEgcmVhbGl6YXIgdW5hIG9wZXJhY2nDs24gY29uIGVsIG1pc21vLg0KDQpgYGB7cn0NCkEgKyA2DQpgYGANCg0KQWwgY29ycmVyIHVuYSBsaW5lYSBjb24gZWwgbm9tYnJlIGRlbCBvYmpldG8sIGxhIGNvbnNvbGEgZGVsIHByb2dyYW1hIG5vcyBtdWVzdHJhIHN1IGNvbnRlbmlkby4gRW50cmUgY29yY2hldGVzIG9ic2VydmFtb3MgZWwgbsO6bWVybyBkZSBvcmRlbiBkZWwgZWxlbWVudG8gZW4gY3Vlc3Rpw7NuLg0KDQpgYGB7cn0NCkIgPC0gMg0KQg0KYGBgDQoNCl9fYGBgPC1gYGBfXyBlcyB1biBvcGVyYWRvciBfX1VuaWRpcmVjY2lvbmFsX18sIGVzIGRlY2lyIHF1ZTogICAgDQoNCmBgYEEgPC0gQmBgYCBpbXBsaWNhIHF1ZSBfX0FfXyB2YSB0b21hciBjb21vIHZhbG9yIGVsIGNvbnRlbmlkbyBkZWwgb2JqZXRvIF9fQl9fLCB5IG5vIGFsIHJldsOpcy4NCg0KYGBge3J9DQpBIDwtIEINCg0KI0Fob3JhIEEgdG9tYSBlbCB2YWxvciBkZSBCLCB5IEIgY29udGludWEgY29uc2VydmFuZG8gZWwgbWlzbW8gdmFsb3INCkEgICANCkINCmBgYA0KDQpFbiBSLCBjdWFuZG8gc2UgZGVmaW5lIHVuIG9iamV0byBjb24gZWwgbWlzbW8gbm9tYnJlIGRlIHVuIG9iamV0byBwcmV2aWFtZW50ZSBleGlzdGVudGUsIGVsIMO6bHRpbW8gcmVlbXBsYXphIGFsIHByaW1lcm8uDQoNCg0KIyMjIE9wZXJhZG9yZXMgYXJpdG3DqXRpY29zOg0KDQotIFN1bWE6ICQrJA0KLSBSZXN0YTogJC0kDQotIENvY2llbnRlOiAkLyQNCi0gTXVsdGlwbGljYWNpw7NuOiAkKiQNCg0KYGBge3J9DQojc3VtYQ0KQSA8LSA1KzYNCkENCiNSZXN0YQ0KQiA8LSA2LTgNCkINCiNjb2NpZW50ZQ0KQyA8LSA2LzINCkMNCiNtdWx0aXBsaWNhY2lvbg0KRCA8LSA2KjINCkQNCmBgYA0KDQoNCiMjIyBPcGVyYWRvcmVzIGzDs2dpY29zIHJlbGFjaW9uYWxlczogDQoNCkxvcyBvcGVyYWRvcmVzIGzDs2dpY29zIHNvbiB1c2Fkb3MgcGFyYSBkZXNjcmliaXIgcmVsYWNpb25lcywgZXhwcmVzYWRhcyBjb21vIHZlcmRhZGVybyAoVFJVRSkgbyBmYWxzbyAoRkFMU0UpLg0KDQotIE1heW9yOiAkPiQNCi0gTWF5b3IgbyBpZ3VhbDogJD49JA0KLSBNZW5vcjogJDwkDQotIE1lbm9yIG8gaWd1YWw6ICQ8PSQNCi0gSWd1YWw6ICQ9PSQNCi0gRGlzdGludG86ICQhPSQNCg0KYGBge3J9DQojUmVkZWZpbmltb3MgbG9zIHZhbG9yZXMgQSB5IEINCkEgPC0gMTANCkIgPC0gMjANCg0KI1JlYWxpemFtb3MgY29tcGFyYWNpb25lcyBsw7NnaWNhcw0KQSA+IEINCkEgPj0gQg0KQSA8IEINCkEgPD0gQg0KQSA9PSBCDQpBICE9IEINCg0KQyA8LSBBICE9IEINCkMNCmBgYA0KDQoNCkNvbW8gbXVlc3RyYSBlbCDDumx0aW1vIGVqZW1wbG8sIGVsIHJlc3VsdGFkbyBkZSB1bmEgb3BlcmFjacOzbiBsw7NnaWNhIHB1ZWRlIGFsbWFjZW5hcnNlIGNvbW8gZWwgdmFsb3IgZGUgdW4gb2JqZXRvLg0KDQoNCiMjIyBPdHJvcyBvcGVyYWRvcmVzIGzDs2dpY29zOiANCg0KLSDDkzogJHwkDQotIFk6ICQmJA0KDQpgYGB7cn0NCiNSZWRlZmluaW1vcyBsb3MgdmFsb3JlcyBBIHkgQg0KQSA8LSAxMA0KQiA8LSAyMA0KI1JlYWxpemFtb3MgY29tcGFyYWNpb25lcyBsw7NnaWNhcw0KDQooQSB8IEIpID4gMzANCihBICYgQikgPD0gMzANCmBgYA0KDQoNCg0KIyMgQ2FyYWN0ZXJlcyBlc3BlY2lhbGVzDQoNCi0gUiBlcyBzZW5zaWJsZSBhIG1hecO6c2N1bGFzIHkgbWluw7pzY3VsYXMsIHRhbnRvIHBhcmEgbG9zIG5vbWJyZXMgZGUgbGFzIHZhcmlhYmxlcywgY29tbyBwYXJhIGxhcyBmdW5jaW9uZXMgeSBwYXLDoW1ldHJvcy4NCi0gTG9zIF9fZXNwYWNpb3MgZW4gYmxhbmNvX18geSBsb3MgX19jYXJyaWFnZSByZXR1cm5fXyAoX2VudGVyXykgbm8gc29uIGNvbnNpZGVyYWRvcyBwb3IgZWwgbGVuZ3VhamUuIExvcyBwb2RlbW9zIGFwcm92ZWNoYXIgcGFyYSBlbXByb2xpamFyIGVsIGPDs2RpZ28geSBxdWUgbGEgbGVjdHVyYSBzZWEgbcOhcyBzaW1wbGVbXjJdLg0KDQpbXjJdOiB2ZXJlbW9zIHF1ZSBleGlzdGVuIGNpZXJ0YXMgZXhjZXBjaW9uZXMgY29uIGFsZ3Vub3MgcGFxdWV0ZXMgbcOhcyBhZGVsYW50ZS4gDQoNCi0gRWwgX19udW1lcmFsX18gYGBgI2BgYCBzZSB1dGlsaXphIHBhcmEgaGFjZXIgY29tZW50YXJpb3MuIFRvZG8gbG8gcXVlIHNlIGVzY3JpYmUgZGVzcHXDqXMgZGVsICMgbm8gZXMgaW50ZXJwcmV0YWRvIHBvciBSLiBTZSBkZWJlIHV0aWxpemFyIHVuICMgcG9yIGNhZGEgbMOtbmVhIGRlIGPDs2RpZ28gcXVlIHNlIGRlc2VhIGFudWxhcg0KDQotIExvcyBfX2NvcmNoZXRlc19fIGBgYFtdYGBgIHNlIHV0aWxpemFuIHBhcmEgYWNjZWRlciBhIHVuIG9iamV0bzoNCiAgICAtIGVuIHVuIHZlY3RvcltuwrAgb3JkZW5dDQogICAgLSBlbiB1bmEgdGFibGFbZmlsYSwgY29sdW1uYV0NCiAgICAtIGVuIHVuYSBsaXN0YVtuwrAgZWxlbWVudG9dDQotIGVsIHNpZ25vIF9fJF9fIHRhbWJpw6luIGVzIHVuIG3DqXRvZG8gZGUgYWNjZXNvLiBQYXJ0aWN1bGFybWVudGUsIGVuIGxvcyBkYXRhZnJhbWVzLCBub3MgcGVybWl0aXJhIGFjY2VkZXIgYSB1bmEgZGV0ZXJtaW5hZGEgY29sdW1uYSBkZSB1bmEgdGFibGENCg0KLSBMb3MgX19wYXLDqW50ZXNpc19fYGBgKClgYGAgc2UgdXRpbGl6YW4gZW4gbGFzIGZ1bmNpb25lcyBwYXJhIGRlZmluaXIgbG9zIHBhcsOhbWV0cm9zLg0KDQotIExhcyBfX2NvbWFzX18gYGBgLCBgYGAgIHNlIHV0aWxpemFuIHBhcmEgc2VwYXJhciBsb3MgcGFyYW1ldHJvcyBhbCBpbnRlcmlvciBkZSB1bmEgZnVuY2nDs24uIA0KDQoqKioNCg0KIyMgVGlwb3MgZGUgT2JqZXRvczogICAgDQpFeGlzdGVuIHVuIGdyYW4gY2FudGlkYWQgZGUgb2JqZXRvcyBkaXN0aW50b3MgZW4gUiwgZW4gbG8gcXVlIHJlc3BlY3RhIGFsIGN1cnNvIHRyYWJhamFyZW1vcyBwcmluY2lwYWxtZW50ZSBjb24gNCBkZSBlbGxvczoNCg0KLSBWYWxvcmVzDQotIFZlY3RvcmVzDQotIERhdGEgRnJhbWVzDQotIExpc3Rhcw0KDQojIyMgVmFsb3Jlcw0KTG9zIHZhbG9yZXMgcHVlZGVuIHNlciBkZSBkaXN0aW50YXMgX2NsYXNlc18gbyBfdGlwb3NfOiAgDQoNCl9fVmFsb3JlcyAiTnVtZXJpYyIgKG51bcOpcmljb3MpX18NCmBgYHtyfQ0KQSA8LSAxDQpjbGFzcyhBKQ0KYGBgDQoNCjxicj4NCiAgDQpfX1ZhbG9yZXMgJ0NoYXJhY3RlcicgKGNhcmFjdGVyKV9fDQpgYGB7cn0NCkEgPC0gIkhvbGEiDQpjbGFzcyhBKQ0KDQpBIDwtICJIb2xhLCDCv3F1w6kgdGFsPyINCmNsYXNzKEEpDQoNCkEgPC0gcGFzdGUoJ0hvbGEsJywgJ8K/cXXDqSB0YWw/Jywgc2VwID0gIiAiKQ0KQQ0KY2xhc3MoQSkNCmBgYA0KDQoNCjxicj4NCiAgDQpfX1ZhbG9yZXMgZGUgdGlwbyAnZmFjdG9yJ19fDQogIA0KRW4gZ2VuZXJhbCwgZXMgdW4gZGF0byBudW3DqXJpY28gcmVwcmVzZW50YWRvIHBvciB1bmEgZXRpcXVldGEuDQoNCmBgYHtyfQ0KdmFsb3IxIDwtICJBIg0KY2xhc3ModmFsb3IxKQ0KDQp2YWxvcjIgPC0gZmFjdG9yKCJBIikNCnZhbG9yMg0KDQojIE90cmEgZm9ybWEgZGUgZGVmaW5pciBhbCBmYWN0b3INCnZhbG9yMiA8LSBmYWN0b3IodmFsb3IxKQ0KdmFsb3IyDQpjbGFzcyh2YWxvcjIpDQoNCiMgVW5hIHByb3BpZWRhZCBkZWwgZmFjdG9yOiBsYXMgZXRpcXVldGFzLg0KdmFsb3IzIDwtIGZhY3RvcigiQSIsDQogICAgICAgICAgICAgICAgIGxhYmVscyA9ICJMZXRyYSBBIikNCmNsYXNzKHZhbG9yMykNCnZhbG9yMw0KYGBgDQoNCg0KPGJyPg0KICANCkxhIGRpZmVyZW5jaWEgZW50cmUgdW4gX2NoYXJhY3Rlcl8geSB1biBfZmFjdG9yXyBlcyBxdWUgZWwgw7psdGltbyB0aWVuZSBzb2xvIGFsZ3Vub3MgdmFsb3JlcyBwZXJtaXRpZG9zIChsZXZlbHMpLCBjb24gdW4gb3JkZW4gaW50ZXJubyBwcmVkZWZpbmlkbyAoZWwgY3VhbCAscG9yIGVqZW1wbG8sIHNlIHJlc3BldGFyw6EgYSBsYSBob3JhIGRlIHJlYWxpemFyIHVuIGdyw6FmaWNvKSAgDQoNCg0KIyMjIFZlY3RvcmVzDQpVbiB2ZWN0b3IgZXMgdW4gY29uanVudG8gZGUgZGF0b3MgZGUgdW4gbWlzbW8gdGlwby4gRW4gb3RyYXMgcGFsYWJyYXMsIGVzIHVuIGNvbmp1bnRvIGRlIHZhbG9yZXMgZGUgbGEgbWlzbWEgY2xhc2UuIFB1ZWRlIGhhYmVyIHZlY3RvcmVzIG7Dum1lcmljb3MsIGNoYXJhY3RlciwgZmFjdG9yZXMuDQpMb3MgdmVjdG9yZXMgY29uc3RpdHV5ZW4gbGEgZXN0cnVjdHVyYSBkZSBkYXRvcyBtw6FzIHNlbmNpbGxhIGRlIFIuDQoNClBhcmEgY3JlYXIgdW4gX192ZWN0b3JfXyB1dGlsaXphbW9zIGVsIGNvbWFuZG8gYGBgYygpYGBgLCBkZSBjb21iaW5hci4NCmBgYHtyfQ0KIyBWZWN0b3IgbnVtw6lyaWNvDQpBIDwtIGMoMSwgMiwgMiwgMiwgMSwgMSwgMSkNCkENCmNsYXNzKEEpDQoNCiMgVmVjdG9yIGRlIGNhcmFjdGVyZXMNCkIgPC0gYygiVW5vIiwgIkRvcyIsICJEb3MiLCAiRG9zIiwgIlVubyIsICJVbm8iLCAiVW5vIikNCkINCmNsYXNzKEIpDQoNCiMgVmVjdG9yIGRlIHRpcG8gZmFjdG9yDQpDIDwtIGFzLmZhY3RvcihBKQ0KQw0KY2xhc3MoQykNCg0KIyBEZWZpbm8gZXRpcXVldGFzIGRlbCB2ZWN0b3IgbnVtw6lyaWNvIG8gY2FyYWN0ZXINCkENCkFfZXRpcXVldGFzIDwtIGZhY3RvcihBLA0KICAgICAgICAgICAgICAgICAgICAgbGFiZWxzID0gYygnVmFyw7NuJywnTXVqZXInKSkNCkFfZXRpcXVldGFzDQpgYGANCg0KDQpDb24gbG9zIHZlY3RvcmVzIG51bcOpcmljb3Mgc2UgcHVlZGVuIGhhY2VyIG9wZXJhY2lvbmVzIGNvbW8sIHBvciBlamVtcGxvOg0KKiBzdW1hcmxlIDIgYSBjYWRhIGVsZW1lbnRvIGRlbCBfX3ZlY3Rvcl9fIGFudGVyaW9yLg0KDQpgYGB7cn0NCkQgPC0gYygxLCAzLCA0KQ0KRCA8LSBEICsgMg0KRA0KYGBgDQoNCg0KKiBzdW1hcmxlIDEgYWwgcHJpbWVyIGVsZW1lbnRvLCAyIGFsIHNlZ3VuZG8sIHkgMyBhbCB0ZXJjZXIgZWxlbWVudG8gZGVsIF9fdmVjdG9yX18gYW50ZXJpb3INCmBgYHtyfQ0KRSA8LSBEICsgMTozICNlc3RvIGVzIGVxdWl2YWxlbnRlIGEgaGFjZXIgMysxLCA1KzIsIDYrOSANCkUNCmBgYA0KDQpgYGAxOjNgYGAgc2lnbmlmaWNhIHF1ZSBxdWVyZW1vcyB0b2RvcyBsb3MgbsO6bWVyb3MgZW50ZXJvcyBkZXNkZSAxIGhhc3RhIDMuIA0KDQo8YnI+DQoNCkVuIFIgcG9kZW1vcyBxdWVkYXJub3MgY29uIGFsZ3Vub3MgZWxlbWVub3MgZGUgbG9zIHZlY3RvcmVzIHBhcmEgdHJhYmFqYXIgY29uIG8gc29icmUgZWxsb3MuDQpQYXJhIGFjY2VkZXIgYSB1biBlbGVtZW50byBkZWwgdmVjdG9yIHBvZGVtb3MgYnVzY2FybG8gYSB0cmF2w6lzIGRlbCBuw7ptZXJvIGRlIG9yZGVuLCBpZGVudGlmaWNhbmRvIGFsIG1pc21vIHV0aWxpemFuZG8gbG9zIHNpZ25vcyBgYGBbIF1gYGANCg0KYGBge3J9DQojIFNpIHF1aWVybyBhbCBlbGVtZW50byAyIGRlbCBvYmpldG8gRToNCkUgDQpFWzJdDQpgYGANCg0KDQpTaSBub3MgaW50ZXJlc2EgcXVlZGFybm9zIGNvbiBkaWNobyB2YWxvciwgYWwgYnVzY2FybG8gbG8gYXNpZ25hbW9zIGEgdW4gbnVldm8gb2JqZXRvLg0KYGBge3J9DQpFX3Bvc2ljaW9uMiA8LSAgRVsyXQ0KRV9wb3NpY2lvbjINCmBgYA0KDQpQYXJhIF9fYm9ycmFyX18gdW4gb2JqZXRvIGRlbCBhbWJpZW50ZSBkZSB0cmFiYWpvLCB1dGlsaXphbW9zIGxhIGZ1bmNpw7NuIF9gYGBybSgpYGBgXw0KYGBge3J9DQpybShFX3Bvc2ljaW9uMikNCiNFX3Bvc2ljaW9uMg0KYGBgDQoNClRhbWJpw6luIHBvZGVtb3MgY2FtYmlhciBlbCB0ZXh0byBkZWwgc2VndW5kbyBlbGVtZW50byBkZSBFLCBwb3IgZWwgdGV4dG8gIlBhYmxvIg0KYGBge3J9DQpFDQpFWzJdIDwtICJQYWJsbyINCkUNCg0KIyBUZW5lciBjdWlkYWRvIGFsIG1vZGlmaWNhciBlbCB0aXBvIGRlIHVubyBkZSBsb3MgdmFsb3JlcyB5IG5vIGVsIGRlIHRvZG9zIGxvcyBkZWwgb2JqZXRvOg0KY2xhc3MoRSkNCmBgYA0KDQojIyMgRGF0YSBGcmFtZXMgKG8gYmFzZXMgZGUgZGF0b3MpDQpVbiBEYXRhIEZyYW1lIGVzIHVuYSBlc3RydWN0dXJhIGRlIGRhdG9zIGRlIDIgZGltZW5zaW9uZXMgbyB0YWJsYSwgZG9uZGUgY2FkYSBjb2x1bW5hIHJlcHJlc2VudGEgdW5hIHZhcmlhYmxlLCB5IGNhZGEgZmlsYSB1bmEgb2JzZXJ2YWNpw7NuLg0KDQpMb3MgZGF0YSBmcmFtZXMgcHVlZGVuIGNvbnRlbmVyIGRhdG9zIGRlIGRpZmVyZW50ZXMgY2xhc2VzLiANClB1ZWRlIHNlciBjb25zaWRlcmFkbyBjb21vIHVuIGNvbmp1bnRvIGRlIHZlY3RvcmVzIGRlIGlndWFsIHRhbWHDsW8sIGRvbmRlIGNhZGEgdmVjdG9yIChjb2x1bW5hKSB0aWVuZSBxdWUgdGVuZXIgZGF0b3MgZGVsIG1pc21vIHRpcG8sIHBlcm8gbGFzIGNsYXNlcyBkZSB2ZWN0b3JlcyBxdWUgY29uZm9ybWFuIGxhIHRhYmxhIHB1ZWRlbiBzZXIgZGlzdGludGFzLiBFbnRvbmNlcywgY2FkYSBvYnNlcnZhY2nDs24gKGZpbGEpIGVzdMOhIGNvbXB1ZXN0YSBwb3IgZGF0b3MgcXVlIHB1ZWRlbiBzZXIgZGUgZGlzdGludG8gdGlwby4NCg0KRXN0ZSBvYmpldG8gZXMgY2VudHJhbCBlbiBlbCBwcm9jZXNvIGRlIHRyYWJham8sIHlhIHF1ZSBlcyBsYSBlc3RydWN0dXJhIG3DoXMgdXNhZGEgcGFyYSByZWFsaXphciBhbsOhbGlzaXMgZGUgZGF0b3MsIHkgc3VlbGUgc2VyIGxhIGZvcm1hIGVuIHF1ZSBzZSBjYXJnYW4gZGF0b3MgZXh0ZXJub3MgcGFyYSB0cmFiYWphciBlbiBlbCBhbWJpZW50ZSBkZSBSLCB5IGVuIHF1ZSBzZSBleHBvcnRhbiBsb3MgcmVzdWx0YWRvcyBkZSBudWVzdHJvcyB0cmFiYWpvLiAgDQoNClZlYW1vcyB1biBlamVtcGxvIGRlIGRhdGEgZnJhbWUgY3JlYWRvIGEgcGFydGlyIGRlIGxhIGNvbWJpbmFjacOzbiBkZSB2ZWN0b3JlczoNCmBgYHtyfQ0KQUdMT01FUkFETyAgPC0gYygzMiwzMywzMywzMywzMikNCg0KU0VYTyAgPC0gIGMoIlZhcm9uIiwiTXVqZXIiLCJNdWplciIsIlZhcm9uIiwiTXVqZXIiKQ0KDQpFREFEICA8LSAgYyg2MCw1NCwxOCwyNywzMikNCg0KRGF0b3MgPC0gZGF0YS5mcmFtZShBR0xPTUVSQURPLCBTRVhPLCBFREFEKQ0KRGF0b3MNCmNsYXNzKERhdG9zKQ0KYGBgDQoNClRhbCBjb21vIGVuIHVuIF9fdmVjdG9yX18gcG9kZW1vcyBhY2NlZGVyIGEgbG9zIGVsZW1lbnRvcyBhIHRyYXbDqXMgZGUgbG9zIGBgYFsgXWBgYCwgZW4gdW4gX19kYXRhZnJhbWVfXyBsbyBoYWNlbW9zIGRlIGxhIGZvcm1hIF9fYGBgW2ZpbGEsIGNvbHVtbmFdYGBgX18uDQoNCkVuIGxvcyBEYXRhLkZyYW1lcyB0ZW5lbW9zLCBwb3IgZGVmaW5pY2nDs24sIG3DoXMgZGUgdW5hIGNvbHVtbmEgKHZhcmlhYmxlKS4gUGFyYSBhY2NlZGVyIGEgYWxndW5hIGRlIGVsbGFzIHBvZGVtb3MgdXRpbGl6YXIgZWwgb3BlcmFkb3IgX19gYGAkYGBgX18uDQpgYGB7cn0NCkRhdG9zWzMsMl0NCkRhdG9zWzQsM10NCg0KRGF0b3MkQUdMT01FUkFETw0KY2xhc3MoRGF0b3MkQUdMT01FUkFETykNCg0KRGF0b3MkQUdMT01FUkFET1syXQ0KYGBgDQoNCsK/cXVlIHBhc2Egc2kgaGFjZW1vcyBgRGF0b3MkQUdMT01FUkFET1szLDJdYCA/DQpgYGByDQpEYXRvcyRBR0xPTUVSQURPWzMsMl0NCmBgYA0KDQpOw7N0ZXNlIHF1ZSBlbCDDumx0aW1vIGNvbWFuZG8gdGllbmUgdW4gbsO6bWVybyBpbmNvcnJlY3RvIGRlIGRpbWVuc2lvbmVzLCBwb3JxdWUgZXN0YW1vcyByZWZpcmllbmRvbm9zIDIgdmVjZXMgYSBsYSBjb2x1bW5hIEFHTE9NRVJBRE8uICAgIA0KDQpBY29yZGUgYSBsbyB2aXN0byBhbnRlcmlvcm1lbnRlLCBlbCBhY2Nlc28gYSBsb3MgX19kYXRhZnJhbWVzX18gbWVkaWFudGUgIGBgYFsgXWBgYCBwdWVkZSB1dGlsaXphcnNlIHRhbWJpw6luIHBhcmEgcmVhbGl6YXIgZmlsdHJvcyAoZGV2b2x2ZXIgZWwgbyBsb3MgdmFsb3JlcyBlbiBmdW5jacOzbiBkZSBvdHJvIHZhbG9yIGRlZmluaWRvKS4gDQpQb3IgZWplbXBsbywgcHVlZG8gdXRpbGl6YXIgbG9zICBgYGBbIF1gYGAgcGFyYSBvYnRlbmVyIGRlbCBfX2RhdGFmcmFtZV9fIGBgYERhdG9zIGBgYCAgdW5pY2FtZW50ZSBsb3MgcmVnaXN0cm9zIGRlbCBBR0xPTUVSQURPIDMyOg0KYGBge3J9DQpEYXRvc1tEYXRvcyRBR0xPTUVSQURPPT0zMiwgXQ0KYGBgDQoNCkxhIGzDs2dpY2EgZGVsIHBhc28gYW50ZXJpb3Igc2Vyw61hOiBBY2NlZG8gYWwgZGF0YWZyYW1lIGBgYERhdG9zYGBgLCBwaWRpZW5kbyDDum5pY2FtZW50ZSBjb25zZXJ2YXIgbGFzIGZpbGFzIChwb3IgZXNvIGxhIGNvbmRpY2nDs24gc2UgdWJpY2EgYSBsYSBfaXpxdWllcmRhXyBkZSBsYSAgYGBgLCBgYGApIHF1ZSBjdW1wbGFuIGVsIHJlcXVpc2l0byBkZSBwZXJ0ZW5lY2VyIGEgbGEgY2F0ZWdvcsOtYSBfXzMyX18gZGUgbGEgdmFyaWFibGUgX19BR0xPTUVSQURPX18uICAgICAgDQoNCkHDum4gbcOhcywgcG9kcsOtYSBhcGxpY2FyIGVsIGZpbHRybyB5IGFsIG1pc21vIHRpZW1wbyBpZGVudGlmaWNhciB1bmEgdmFyaWFibGUgZGUgaW50ZXLDqXMgcGFyYSBsdWVnbyByZWFsaXphciB1biBjw6FsY3VsbyBzb2JyZSBhcXVlbGxhLiBQb3IgZWplbXBsbywgcG9kcsOtYSBjYWxjdWxhciBsYSBtZWRpYSBkZSBsYSBlZGFkIHBhcmEgYXF1ZWxsYXMgcGVyc29uYXMgcXVlIHJlc2lkZW4gZW4gZWwgYWdsb21lcmFkbyAzMi4NCg0KYGBgcg0KIyMjUG9yIHNlcGFyYWRvDQpFZGFkX0FnbG8zMiA8LSBEYXRvcyRFREFEW0RhdG9zJEFHTE9NRVJBRE89PTMyXQ0KRWRhZF9BZ2xvMzINCmBgYA0KDQpgYGB7cn0NCiNtZWFuKEVkYWRfTWllbWJybzEpDQoNCiMgT3RyYSBmb3JtYSBkZSBsb2dyYXIgZWwgbWlzbW8gcmVzdWx0YWRvDQpFZGFkX0FnbG8zMiA8LSBtZWFuKERhdG9zJEVEQURbRGF0b3MkQUdMT01FUkFETz09MzJdKQ0KYGBgDQoNCkxhIGzDs2dpY2EgZGUgZXN0YSBzaW50YXhpcyBzZXLDrWE6ICJNZSBxdWVkw7MgY29uIGxhIHZhcmlhYmxlIF9fRURBRF9fLCBjdWFuZG8gbGEgdmFyaWFibGUgQUdMT01FUkFETyBzZWEgaWd1YWwgYSBfXzMyX18sIGx1ZWdvIGNhbGN1bG8gbGEgbWVkaWEgZGUgZGljaG9zIHZhbG9yZXMiDQoNCjxicj4NCg0KIyMjIExpc3Rhcw0KDQpDb250aWVuZW4gdW5hIGNvbmNhdGVuYWNpw7NuIGRlIG9iamV0b3MgZGUgY3VhbHF1aWVyIHRpcG8uIEFzw60gY29tbyB1biB2ZWN0b3IgY29udGllbmUgdmFsb3JlcywgdW4gZGF0YWZyYW1lIGNvbnRpZW5lIHZlY3RvcmVzLCB1bmEgbGlzdGEgcHVlZGUgY29udGVuZXIgZGF0YWZyYW1lcywgcGVybyB0YW1iacOpbiB2ZWN0b3JlcywgbyB2YWxvcmVzLCB5IF90b2RvIGVsbG8gYSBsYSB2ZXpfDQpgYGB7cn0NCkxJU1RBIDwtIGxpc3QoQSxCLEMsRCxFLERhdG9zJEFHTE9NRVJBRE8sIERGID0gRGF0b3MpDQpMSVNUQQ0KYGBgDQoNClRhbCBjb21vIHBhcmEgY29uIGxvcyBWZWN0b3JlcyB5IGxvcyBEYXRhLkZyYW1lcywgcG9kZW1vcyBhY2NlZGVyIGEgdW4gZWxlbWVudG8gZGUgdW5hIGxpc3RhLCB1dGlsaXphbmRvIGVsIG9wZXJhZG9yIF9fYGBgJGBgYF9fOg0KYGBge3J9DQpMSVNUQSRERg0KTElTVEEkREYkRURBRA0KTElTVEEkREYkRURBRFsyXQ0KYGBgDQoNClRhbWJpw6luIHNlIHB1ZWRlbiB1c2FyIGNvcmNoZXRlcyBkb2JsZXMgX19gYGBbW11dYGBgX18gcGFyYSBhY2NlZGVyIGEgbG9zIGRpc3RpbnRvcyBlbGVtZW50b3MgZGUgdW5hIGxpc3RhLg0KYGBge3J9DQpMSVNUQVtbNl1dDQpgYGANCg0KTyBwYXJhIGFjY2VkZXIgYSB1biB2YWxvci92ZWN0b3IgKGRlcGVuZGllbmRvIGRlbCB0aXBvIGRlIGVsZW1lbnRvIGRlIGxhIGxpc3RhKSBkZSB1biBvYmpldG8gZGUgbGEgbGlzdGE6DQpgYGB7cn0NCkxJU1RBW1s2XV1bMV0NCg0KTElTVEFbWzddXVsyXQ0KDQpMSVNUQVtbN11dWzIsMV0NCmBgYA0KDQojIyBGdW5jaW9uZXMgKGxhcyBoZXJyYW1pZW50YXMgZGVsIGFybWFyaW8pOg0KTGFzIGZ1bmNpb25lcyBzb24gc2VyaWVzIGRlIHByb2NlZGltaWVudG9zIGVzdGFuZGFyaXphZG9zLCBxdWUgdG9tYW4gY29tbyBpbXB1dCBkZXRlcm1pbmFkb3MgYXJndW1lbnRvcyBhIGZpamFyIHBvciBlbCB1c3VhcmlvIChsbGFtYWRvcyBwYXLDoW1ldHJvcyksIHkgZGV2dWVsdmVuIHVuIHJlc3VsdGFkbyBhY29yZGUgYSBsYSBhcGxpY2FjacOzbiBkZSBkaWNob3MgcHJvY2VkaW1pZW50b3MuIFN1IGzDs2dpY2EgZGUgZnVuY2lvbmFtaWVudG8gZXM6ICAgDQpgYGBmdW5jaW9uKGFyZ3VtZW50bzEgPSBhcmcxLCBhcmd1bWVudG8yID0gYXJnMilgYGAgICAgICANCg0KQSBsbyBsYXJnbyBkZWwgY3Vyc28gaXJlbW9zIHZpZW5kbyBudW1lcm9zYXMgZnVuY2lvbmVzLCBzZWfDum4gbG8gcmVxdWllcmFuIGxvcyBkaXN0aW50b3MgZWplcmNpY2lvcy4gU2luIGVtYmFyZ28sIHZlYW1vcyBhaG9yYSBhbGd1bm9zIGVqZW1wbG9zIHBhcmEgY29tcHJlbmRlciBzdSBmdW5jaW9uYW1pZW50bzogICAgDQoNCi0gcGFzdGUoKSA6IGNvbmNhdGVuYSB1bmEgc2VyaWUgZGUgY2FyYWN0ZXJlcywgaW5kaWNhbmRvIHBvciDDumx0aW1hIGluc3RhbmNpYSBjb21vIHNlcGFyYXIgYSBjYWRhIHVubyBkZSBlbGxvcyAgICAgICAgDQotIHBhc3RlMCgpOiBjb25jYXRlbmEgdW5hIHNlcmllIGRlIGNhcmFjdGVyZXMgc2luIHNlcGFyYXINCi0gc3VtKCk6IHN1bWEgZGUgdG9kb3MgbG9zIGVsZW1lbnRvcyBkZSB1biB2ZWN0b3IgICANCi0gbWVhbigpIHByb21lZGlvIGFyaXRtw6l0aWNvIGRlIHRvZG9zIGxvcyBlbGVtZW50b3MgZGUgdW4gdmVjdG9yICAgDQpgYGB7cn0NCnBhc3RlKCJQZWdhIiwiZXN0YXMiLCA0LCAicGFsYWJyYXMiLCBzZXAgPSAiICIpDQoNCiNQdWVkbyBjb25jYXRlbmFyIGNhcmFjdGVyZXMgYWxtYWNlbmFkb3MgZW4gb2JqZXRvcw0KYSA8LSBjKDEsIDIsIDMpDQpiIDwtICJjb24iDQpjIDwtIGMoNCwgNSwgNikNCg0KcGFzdGUoYSxiLGMsc2VwID0gIi0iKQ0KDQojIFBhc3RlMCBwZWdhIGxvcyBjYXJhY3RlcmVzIHNpbiBzZXBhcmFkb3INCnBhc3RlMChhLGIsYykNCg0KIyDCv1RlIGFjb3Jkw6FzIGRlbCBjb21hbmRvIHF1ZSB1c2Ftb3M/DQoxOjUNCg0KIyBGdW5jacOzbiBwYXJhIHN1bWFyDQpzdW0oMTo1KQ0KDQojIFBhcmEgY2FsY2xhciBtZWRpYXMNCm1lYW4oMTo1KQ0KYGBgDQoNCiMgSW5zdGFsYWNpw7NuIGRlIHBhcXVldGVzIGNvbXBsZW1lbnRhcmlvcyBhbCBSIEJhc2UgKMKhbcOhcyBjYWphcyBkZSBoZXJyYW1pZW50YXMgcGFyYSBlbCBhcm1hcnJpbyEpDQoNCkhhc3RhIGFxdcOtIGhlbW9zIHZpc3RvIG3Dumx0aXBsZXMgZnVuY2lvbmVzIHF1ZSBlc3TDoW4gY29udGVuaWRhcyBkZW50cm8gZGVsIGxlbmd1YWplIGLDoXNpY28gZGUgUi4gQWhvcmEgYmllbiwgYWwgdHJhdGFyc2UgZGUgdW4gc29mdHdhcmUgbGlicmUsIGRpc3RpbnRvcyB1c3VhcmlvcyBkZSBSIGNvbnRyaWJ1eWVuIHNpc3RlbcOhdGljYW1lbnRlIGEgZXhwYW5kaXIgZXN0ZSBsZW5ndWFqZSBtZWRpYW50ZSBsYSBjcmVhY2nDs24geSBhY3R1YWxpemFjacOzbiBkZSBfX3BhcXVldGVzX18gY29tcGxlbWVudGFyaW9zLiBMw7NnaWNhbWVudGUsIGxvcyBtaXNtb3Mgbm8gZXN0w6FuIGluY2x1aWRvcyBlbiBsYSBpbnN0YWxhY2nDs24gaW5pY2lhbCBkZWwgcHJvZ3JhbWEsIHBlcm8gcG9kZW1vcyBkZXNjYXJnYXJsb3MgZSBpbnN0YWxhcmxvcyBjb24gZWwgc2lndWllbnRlIGNvbWFuZG86ICAgDQpgYGAgDQppbnN0YWxsLnBhY2thZ2VzKCJub21icmVfZGVsX3BhcXVldGUiKSANCmBgYA0KQWwgZWplY3V0YXIgZWwgY29tYW5kbyBzZSBkZXNjYXJnYXLDoW4gZGUgbGEgcGFnaW5hIGRlIFtDUkFOXSh3d3cuY3Jhbi5yLXByb2plY3Qub3JnKSBsb3MgYXJjaGl2b3MgY29ycmVzcG9uZGllbnRlcyBhbCBwYXF1ZXRlIGhhY2lhIGVsIGRpcmVjdG9yaW8gZW4gZG9uZGUgaGF5YW1vcyBpbnN0YWxhZG8gZWwgcHJvZ3JhbWEuIFTDrXBpY2FtZW50ZSBsb3MgYXJjaGl2b3Mgc2UgZW5jb250cmFyw6FuIGVuICoqQzpcUHJvZ3JhbSBGaWxlc1xSXFItMy41LjBcbGlicmFyeVwqKiwgc2llbXByZSBjb24gbGEgdmVyc2nDs24gZGVsIHByb2dyYW1hIGNvcnJlc3BvbmRpZW50ZS4gICAgICAgICAgICAgIA0KDQpMb3MgcGFxdWV0ZXMgc8OzbG8gc2UgaW5zdGFsYW4gdW5hIHZleiBlbiBsYSBjb21wdXRhZG9yYSAoc2kgY2FtYmlhcyBkZSBjb21wdXRhZG9yYSwgdGVuw6lzIHF1ZSB2b2x2ZXIgYSBpbnN0YWxhcmxvKS4gVW5hIHZleiBpbnN0YWxhZG8gZWwgcGFxdWV0ZSwgY2FkYSB2ZXogcXVlIGFicmFtb3MgdW5hIG51ZXZhIHNlc2nDs24gZGUgUiB5IHF1ZXJyYW1vcyB1dGlsaXphciBlbCBtaXNtbyBkZWJlbW9zICoqY2FyZ2FybG8gYWwgYW1iaWVudGUgZGUgdHJhYmFqbyoqIG1lZGlhbnRlIGxhIHNpZ3VpZW50ZSBmdW5jacOzbjoNCmBgYCANCmxpYnJhcnkobm9tYnJlX2RlbF9wYXF1ZXRlKQ0KYGBgDQpOw7N0ZXNlIHF1ZSBhbCBjYXJnYXIvYWN0aXZhciBlbCBwYXF1ZXRlIG5vIHNvbiBuZWNlc2FyaWFzIGxhcyBjb21pbGxhcy4NCg0KIyBQYXF1ZXRlcyBhIHV0aWxpemFyIGEgbG8gbGFyZ28gZGVsIGN1cnNvOg0KDQpQYXJhIHF1aWVuZXMgZXN0ZW4gdHJhYmFqYW5kbyBjb24gc3VzIGNvbXB1dGFkb3JhcyBwZXJzb25hbGVzLCBkZWphbW9zIGEgY29udGludWFjacOzbiB1biBsaXN0YWRvIGRlIGxvcyBwYXF1ZXRlcyBjb21wbGVtZW50YXJpb3MgZGVsIFIgYmFzZSBxdWUgdXRpbGl6YXJlbW9zIGEgbG8gbGFyZ28gZGVsIGN1cnNvLiBDb21vIGxhIGluc3RhbGFjacOzbiByZXF1aWVyZSBkZXNjYXJnYXIgbcO6bHRpcGxlcyBhcmNoaXZvcyBkZSBpbnRlcm5ldCByZWNvbWVuZGFtb3MgaGFjZXJsbyBjdWFuZG8gZGlzcG9uZ2FuIGRlIHVuYSBidWVuYSBjb25leGnDs24uIENvbiBlbCBzaWd1aWVudGUgY29tYW5kbyBwb2Ryw61hbiBpbnN0YWxhcmxvcyB0b2RvcyBkZSB1bmEgdmV6OiAgIA0KDQpgYGANCmluc3RhbGwucGFja2FnZXMoYygidGlkeXZlcnNlIiwib3Blbnhsc3giLCdnZ3Bsb3QyJywnZ2d0aGVtZXMnLCAnZ2dyZXBlbCcsJ2dnYWx0Jywna2FibGVFeHRyYScsICdybWFya2Rvd24nKSkNCmBgYA0KDQogIA0KICA=